#This module is for applying subgradient algorithm
#input: tolerance
#output: the list of primal solution, dual solution
#it internally calls the solvelr function with different lambda values
#to get primal and dual solutions
import sys
from lagrange import *
#print getidx(1,2,5)

iter = 0
N = 10
b = 40
t = 1
#report = False
report = True
seed = int(sys.argv[1])
dual_rows = ["u" + str(i+1) for i in range(N)] + ["v" + str(i+1) for i in range(N)]
#dual_rows = ["v" + str(i+1) for i in range(N)]
#dual_rows = ["u" + str(i+1) for i in range(N)] + ["k"]

#l = np.ones( len(dual_rows) )
l = np.zeros( len(dual_rows) )
rho = 0.9
eps = 1

print "solve the problem by cplex"
prob_org = initip(seed, N, b)
prob_org.parameters.mip.display.set(0)
prob_org.solve()
z_opt_true = prob_org.solution.get_objective_value()

if report == True:
    print prob_org.solution.get_values()
    print prob_org.solution.get_objective_value()

prob_org = initip(seed, N, b)
prob_org.set_problem_type(type=0)
prob_org.solve()
z_opt_lp = prob_org.solution.get_objective_value()
#prob_org.write("org.lp")

print "solve the problem by LR"

prob = initip( seed, N, b)

A, b, sen, c = initlr(prob, dual_rows)
#print "c is ", c
prob.parameters.mip.display.set(0)

z = 0
z_opt = 1000000

iter_opt_cnt = 0
iter_opt = 0
#a while loop for solving the lr(lambda)
l_pos_ind = []
l_eql_ind = []
l_neg_ind = []
print sen
for i in range( len(sen) ):
    if sen[i] == "E":
        l_eql_ind.append(i)
    elif sen[i] == "L":
        l_pos_ind.append(i)
    else:
        l_neg_ind.append(i)

print l_pos_ind
print l_eql_ind
print l_neg_ind

while True:
    #print "c is ", c
        
    if iter_opt_cnt > 10:
        print "Reach iteration limit"
        break
    
    solvelr(prob, l, A, b, c)

    # Get the current optimal solutions
    x = np.array( prob.solution.get_values() )
    z = prob.solution.get_objective_value()
    g = gap(x, A, b)
    
    # Report values at current iteration
    if report == True:
        print "iteration ", iter,"----------------"
        print "t is", t
        print "l is", l
        print "z is", z
#        print "x is", x
        print "g is", g
        print 
    #prob.write("lr"+str(iter)+".lp")

    if opt_test(x, l, A, b, sen):
        print "Optimal solution found"
        z_opt = z
        iter_opt = iter
        break

    # Can be wrapped up as a function
    # Update lambda parameters
#    l = np.maximum( np.zeros(len(l)), l - t * g)
    temp_l = l - t*g
    if len(l_pos_ind) != 0:
        l[l_pos_ind] = np.maximum( np.zeros(len(l_pos_ind) ), temp_l[l_pos_ind])

    if len(l_eql_ind) != 0:
        l[l_eql_ind] = temp_l[l_eql_ind]

    if len(l_neg_ind) != 0:
        l[l_neg_ind] = np.minimum( np.zeros(len(l_neg_ind) ), temp_l[l_neg_ind])

    # Update step length by geometric series
    t = t * rho

    # Update step length by another rule by variable fixing
    #    t = eps * z - 
    
    # Update z*
    if z < z_opt:
        z_opt = z
        iter_opt = iter
        iter_opt_cnt = 1
    elif z == z_opt:
        iter_opt = iter
        iter_opt_cnt = iter_opt_cnt + 1
    else:
        iter_opt_cnt = iter_opt_cnt + 1

    iter = iter+1

r_opt_gap = abs(z_opt_true - z_opt)/ z_opt_true

print "-------------------------"
print "----    Summary:   ------"
print "-------------------------"
print "true ip optimal solution", z_opt_true, "\n" 
print "true lp optimal solution", z_opt_lp, "\n"
print "  lr optimal solution", z_opt, "at iteration", iter_opt, "\n"
print "total iterations", iter, "\n"
print "relative optimality gap", r_opt_gap
    



#format the output
